package korlibs.korge.gradle.generate

import korlibs.text
import java.io.File

object TemplateGenerator {
    @JvmStatic
    @JvmOverloads
    fun synchronizeNew(file: File, includeByte: Boolean = true, includeFloat: Boolean = true, includeGeneric: Boolean = true, includeShort: Boolean = false, includeLong: Boolean = false, includeChar: Boolean = false, includeBoolean: Boolean = false, includeBit: Boolean = false) {
        val STRING_START = "// GENERIC TEMPLATE //////////////////////////////////////////\n"
        val STRING_END = "// END OF GENERIC TEMPLATE ///////////////////////////////////\n"
        val NOTICE = "// AUTOGENERATED: DO NOT MODIFY MANUALLY STARTING FROM HERE!\n"

        val text = file.readText()
        val header = text.substringBefore(STRING_START)
        val template = text.substringAfter(STRING_START).substringBefore(STRING_END)
        val types = ArrayList<String>().apply {
            add("Int")
            add("Double")
            if (includeFloat) add("Float")
            if (includeByte) add("Byte")
            if (includeChar) add("Char")
            if (includeShort) add("Short")
            if (includeLong) add("Long")
            if (includeBoolean) add("Boolean")
            // if (includeBit) add("Bit")
        }
        val rest = types.joinToString("\n\n") {
            "// $it\n\n" + template.replaceTemplate(it)
        }

        val generated = "$header$STRING_START$template$STRING_END\n$NOTICE\n$rest".trimEnd() + "\n"
        if (file.text != generated) {
            file.text = generated
        }
    }

    @JvmOverloads
    @JvmStatic
    fun synchronize(src: File, dst: File, includeFloat: Boolean = true, includeGeneric: Boolean = false, includeByte: Boolean = false) {
        val content = src.readText()
        val parts = content.split("// GENERIC\n")
        val head = parts[0].trim()
        val generic = parts.getOrElse(1) { "" }

        val types = listOf("Int", "Double") + (if (includeFloat) listOf("Float") else listOf()) + (if (includeByte) listOf("Byte") else listOf())

        /*
        dst.writeText(
            ("$head\n\n// AUTOGENERATED: DO NOT MODIFY MANUALLY!\n\n" +
                (if (includeGeneric) generic + "\n\n" else "") +
                types.joinToString("\n\n") { "// $it\n" + generic.replaceTemplate(it) })
                .restoreCollectionKinds()
        )
         */
    }

    fun String.restoreCollectionKinds(): String = this
        .restoreCollectionKinds("Byte")
        .restoreCollectionKinds("Int")
        .restoreCollectionKinds("Float")
        .restoreCollectionKinds("Double")

    fun String.restoreCollectionKinds(kind: String): String {
        return this.replace("${kind}List", "List<$kind>")

            .replace("${kind}MutableIterator", "MutableIterator<$kind>")
            .replace("${kind}MutableCollection", "MutableCollection<$kind>")

            .replace("${kind}Iterable", "Iterable<$kind>")
            .replace("${kind}Iterator", "Iterator<$kind>")
            .replace("${kind}Collection", "Collection<$kind>")

            .replace("${kind}Comparable", "Comparable<$kind>")
            .replace("${kind}Comparator", "Comparator<$kind>")
    }

    fun String.replaceTemplate(kind: String): String {
        val lkind = kind.toLowerCase()
        return this
            .replace("FastArrayList", "ArrayList")
            .replace("arrayOfNulls<Any>", "${kind}Array")
            .replace("arrayOfNulls<TGen>", "${kind}Array")
            //.replace("arrayOfNulls", "${kind}Array")
            .replace("<reified TGen>", "")
            .replace("<TGen : Any>", "")
            .replace("<*/*_TGen_*/>", "")
            .replace("null/*TGen*/", when (kind) {
                "Boolean" -> "false"
                "Byte" -> "0.toByte()"
                "Short" -> "0.toShort()"
                "Char" -> "'\\u0000'"
                "Int" -> "0"
                "Long" -> "0L"
                "Float" -> "0f"
                "Double" -> "0.0"
                else -> "0"
            })
            .replace("<reified TGen : Comparable<TGen>>", "")
            .replace("<TGen : Comparable<TGen>>", "")
            .replace("Iterable<TGen>", "Iterable<$kind>")
            .replace("Collection<TGen>", "Collection<$kind>")
            .replace("fun <TGen>", "fun")
            .replace("arrayListOf<TGen>", "${lkind}ArrayListOf")
            //.replace("List<TGen>", "${kind}ArrayList")
            .replace("Array<TGen>", "${kind}Array")
            .replace("Array<Any>", "${kind}Array")
            .replace("Array<Any?>", "${kind}Array")
            .replace("Array<out TGen>", "${kind}Array")
            .replace(Regex("""(\w+)<TGen>""")) {
                val base = it.groupValues[1]
                val name = base.replace("TGen", "")
                when (base) {
                    "List" -> "List<$kind>"
                    "Iterator" -> "Iterator<$kind>"
                    "MutableIterator" -> "MutableIterator<$kind>"
                    "ListIterator" -> "ListIterator<$kind>"
                    else -> "$kind$name"
                }
            }
            .replace(Regex("""(\w+)<\*/\*TGen\*/>""")) {
                val base = it.groupValues[1]
                val name = base.replace("TGen", "")
                when (base) {
                    "List" -> "List<$kind>"
                    "Iterator" -> "Iterator<$kind>"
                    "MutableIterator" -> "MutableIterator<$kind>"
                    "ListIterator" -> "ListIterator<$kind>"
                    else -> "$kind$name"
                }
            }
            .replace(": TGen", ": $kind")
            .replace("-> TGen", "-> $kind")
            .replace("as TGen", "as $kind")
            .replace("(TGen)", "($kind)")
            .replace("TGen, ", "$kind, ")
            .replace("TGen", kind)
            .replace("tgen", lkind)

    }

}
